package cn.bitkit.mybatis.builder;

import java.util.Map;
import java.util.StringJoiner;

import cn.bitkit.base.constants.DialectType;
import cn.bitkit.mybatis.DialectContext;
import cn.bitkit.mybatis.CriteriaHandler;
import cn.bitkit.mybatis.query.QueryCriteria;
import cn.bitkit.mybatis.entity.EntityClass;
import cn.bitkit.mybatis.base.BaseSqlBuilder;

/**
 * @author changbo
 */
public class SelectPageBuilder implements BaseSqlBuilder {

	@Override
	public boolean supportLinkTable() {
		return true;
	}

	@Override
	public String build(EntityClass entityClass, Map<String, Object> paramMap) {
		StringJoiner sql = new StringJoiner(" \n");
		sql.add("SELECT " + CriteriaHandler.getSelect(entityClass, paramMap));
		sql.add("FROM " + CriteriaHandler.getFrom(entityClass, paramMap));
		sql.add("<where>");
		sql.add(CriteriaHandler.getWhereSql(paramMap));
		sql.add("</where>");
		sql.add(CriteriaHandler.getGroupBy(paramMap));
		sql.add(CriteriaHandler.getOrderBy(paramMap));
		return getPageSql(paramMap, sql.toString());
	}

	private String getPageSql(Map<String, Object> map, String query){
		QueryCriteria criteria = (QueryCriteria) map.get("criteria");
		if(DialectType.mysql.equals(DialectContext.getDialectType())) {
			return getMysql(criteria, query);
		}
		if(DialectType.postgresql.equals(DialectContext.getDialectType())) {
			return getPostgresql(criteria, query);
		}
		if(DialectType.oracle.equals(DialectContext.getDialectType())) {
			return getOracle(criteria, query);
		}
		return getMysql(criteria, query);
	}

	private String getOracle(QueryCriteria criteria, String query){
		long start = criteria.getOffset();
		long end = criteria.getOffset() + criteria.getLimit();
		StringJoiner sql = new StringJoiner("\n");
		sql.add("SELECT PAGE_T2.* FROM (");
		sql.add("  SELECT PAGE_T1.*, ROWNUM");
		sql.add("  FROM ( ");
		sql.add(query);
		sql.add("  ) PAGE_T1");
		sql.add("  WHERE PAGE_T1.ROWNUM <= " + end);
		sql.add(") PAGE_T2");
		sql.add("WHERE PAGE_T2.ROWNUM >= " + start);
		return sql.toString();
	}

	private String getPostgresql(QueryCriteria criteria, String query){
		return query + "\n LIMIT " + criteria.getLimit() + " OFFSET " + criteria.getOffset();
	}

	private String getMysql(QueryCriteria criteria, String query){
		return query + "\n LIMIT " + criteria.getOffset() + ", " + criteria.getLimit();
	}

}
